import json
import re
from datetime import datetime
import asyncio

import requests
from urllib import parse
from django.http import HttpResponse, JsonResponse
from django.conf import settings
from django.contrib.auth import hashers
from django.db import transaction
from django.db.models import F
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView, Response, status
from asgiref.sync import sync_to_async


from apps.common.account.models import Account

from rest_framework_simplejwt.tokens import RefreshToken


def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)

    return {
        'refresh_token': str(refresh),
        'token': str(refresh.access_token),
    }


def get_openid(code):
    """ 微信根据code 获取openid"""
    url = f"https://api.weixin.qq.com/sns/jscode2session?appid={settings.APP_ID}&secret={settings.APP_SECRET}&js_code" \
          f"={code}&grant_type=authorization_code"
    result = requests.get(url)
    res = json.loads(result.text)  # 得到的数据格式为：{'session_key': '', 'openid': ''}
    openid = res.get('openid', None)
    return openid


class WechatLoginView(APIView):

    def post(self, request):
        """ 微信登陆 """
        code = request.data.get('code', None)
        if not code:
            return Response({'message': '缺少code'}, status=status.HTTP_400_BAD_REQUEST)
        openid = get_openid(code)
        if not openid:
            return Response({'message': '请求微信服务器失败，请重试'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)

        user = Account.objects.filter(mini_program_openid=openid).first()
        if not user:
            return Response({'openid': openid, 'message': '找不到该微信用户'}, status=status.HTTP_400_BAD_REQUEST)

        data = get_tokens_for_user(user)
        user.last_login = datetime.now()  # 修改该账号的最近登陆时间
        user.save()
        user_data = {'username': user.username, 'realname': user.realname, 'openid': openid}
        data.update(user_data)

        return Response({'data': data, 'message': '登录成功'})


class MiniProgramBindAccount(APIView):

    def post(self, request):
        """ 传入账号密码，将该账号与该用户的小程序绑定 """
        username = request.data.get('username', '')
        password = request.data.get('password', '')
        mini_program_openid = request.data.get('openid', '')
        if not all([username, password, mini_program_openid]):
            return Response({'message': '错误，必须输入账号和密码。'}, status=status.HTTP_400_BAD_REQUEST)
        existed = Account.objects.filter(mini_program_openid=mini_program_openid).exists()
        if existed:
            return Response({'message': '错误，该微信已绑定账号, 一个微信只支持绑定一个账号。'},
                            status=status.HTTP_400_BAD_REQUEST)

        # 查询该用户并绑定
        try:
            user = Account.objects.get(username=username)

            if not hashers.check_password(password, user.password):
                return Response({'message': '密码错误'}, status=status.HTTP_400_BAD_REQUEST)
            if not user.is_active:
                return Response({'message': '账号已被冻结'}, status=status.HTTP_400_BAD_REQUEST)

            user.last_login = datetime.now()
            user.mini_program_openid = mini_program_openid
            user.save()

        except Account.DoesNotExist:
            return Response({'message': '账号错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 返回jwt和用户的数据
        data = get_tokens_for_user(user)
        user_data = {'username': user.username, 'realname': user.realname}
        data.update(user_data)
        return Response({'data': data, 'message': '绑定成功'}, status=status.HTTP_200_OK)
